#include "test_album.h"

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

enum { kNone = -1, kObj, kMaterial, kScale, kTranslate, kRotate };
enum { kKd, kKa, kKs };

int ParseState(const char *tag) {
  if (0 == strcmp(tag, "Obj")) return kObj;
  else if (0 == strcmp(tag, "Material")) return kMaterial;
  else if (0 == strcmp(tag, "Scale")) return kScale;
  else if (0 == strcmp(tag, "Translate")) return kTranslate;
  else if (0 == strcmp(tag, "Rotate")) return kRotate;
  else return kNone;
}

char buff[256];

int ParseTriplet(FILE *fp, float *triplet) {
  float r, g, b;
  int ret = fscanf(fp, "%f %f %f", &r, &g, &b);
 /* Kx[0] = r;
  Kx[1] = g;
  Kx[2] = b;*/
  printf("(%f %f %f)\n", r, g, b);

  if (3 != ret) {
    printf("wrong triplet\n");
    return EOF;
  }
  return ret;
}

int ParseTriplet(FILE *fp, int *state, float *triplet) {
  int ret = fscanf(fp, "%s", buff);
  if (EOF == ret) return ret;

  int temp_state = ParseState(buff);
  if (kNone != temp_state) {
    *state = temp_state;
    return ret;
  }

   // should be material description
  if (0 != strcmp("(", buff)) {
    // not started with '(', error
    printf("wrong beginning\n");
    return EOF;
  }  
  
  ret = ParseTriplet(fp, triplet);    

  ret = fscanf(fp, "%s", buff);
  if (EOF != ret && 0 != strcmp(")", buff)) {
    printf("triplet not complete\n");
    return EOF;
  }
  return ret;  
}

int ParseObjs(FILE *fp, int *state) {  
  int ret = fscanf(fp, "%s", buff);
  while (EOF != ret) {
    // other state or obj files
    int temp_state = ParseState(buff);
    if (kNone != temp_state) {
      *state = temp_state;
      break;
    }
    
    // load model;
    printf("model: %s\n", buff);
    
    ret = fscanf(fp, "%s", buff);
  }
  return ret;
}

int ParseMaterial(FILE *fp, int *state) {
  int ret = fscanf(fp, "%s", buff);
  while (EOF != ret) {
    int temp_state = ParseState(buff);
    if (kNone != temp_state) {
      *state = temp_state;
      break;
    }
    if (0 != strcmp("{", buff)) {
      // not started with '{', error
      printf("wrong material beginning\n");
      return EOF;
    }
    ret = fscanf(fp, "%s", buff);
    while (EOF != ret) {
      if (0 == strcmp(buff, "Kd")) {
        ret = ParseTriplet(fp, NULL);
      } else if (0 == strcmp(buff, "Ks")) {
        ret = ParseTriplet(fp, NULL);
      } else if (0 == strcmp(buff, "Ka")) {
        ret = ParseTriplet(fp, NULL);
      } else if (0 == strcmp("}", buff)) {
        // load material
        break;
      } else {
        // not one of { Kd, Ka, Ks }, error
        printf("wrong material component\n");
        return EOF;
      }
      ret = fscanf(fp, "%s", buff);
    }
    ret = fscanf(fp, "%s", buff);
  }
  return ret;
}

int ParseScale(FILE *fp, int *state) {
  int ret = fscanf(fp, "%s", buff);
  while (EOF != ret) {
    int temp_state = ParseState(buff);
    if (kNone != temp_state) {
      *state = temp_state;
      break;
    }    
      // store scales
    float scale = atof(buff); 
    printf("scale: %f\n", scale);
    
    ret = fscanf(fp, "%s", buff);
  }
  return ret;
}

int ParseTranslate(FILE *fp, int *state) {
  int ret = 0;
  do {
    ret = ParseTriplet(fp, state, NULL);
  } while (EOF != ret && kTranslate == *state);
  return ret;
}

int ParseRotate(FILE *fp, int *state) {
  int ret = 0;
  do {
    ret = ParseTriplet(fp, state, NULL);
  } while (EOF != ret && kRotate == *state);
  return ret;
}

bool ParseScene(const char *file) { 
  FILE *fp = fopen(file, "r");
  if (NULL == fp) {
    printf("Can't open file, %s\n", file);
    return EOF;
  }

  int state = kNone;
  int temp_state = kNone;  
  int ret = fscanf(fp, "%s", buff);
  while (EOF != ret) {
    switch (state) {
    case kObj:
      ret = ParseObjs(fp, &state); 
      break;
    case kMaterial:
      ret = ParseMaterial(fp, &state);
      break;
    case kScale:
      ret = ParseScale(fp, &state);
      break;
    case kTranslate:
      ret = ParseTranslate(fp, &state);
      break;
    case kRotate:
      ret = ParseRotate(fp, &state);
      break; 
    case kNone:
      state = ParseState(buff);
      break;
    default:
      break;
    }
  }
  fclose(fp);
}

namespace ct {
  void SceneParserTest::Run(int argc, char *argv[]) {
    ParseScene("boxes.txt");
  }
} // ct
